#!BPY

# ase code for Blender 2 Xreal Suite,
# by Adrian 'otty' Fuhrmann,
# based on 'goofos' ase exporter


import Blender, time, math, sys as osSys #os
from Blender import sys, Window, Draw, Scene, Mesh, Material, Texture, Image, Mathutils



#============================================
#           Write!
#============================================

def writeASEFile(filename, spawn_list):
   start = time.clock()
   print_boxed('---------Start of Export------------')
   print 'Export Path: ' + filename

   global exp_list, Tab, idnt, imgTable, worldTable

   exp_list =[]
   Tab = "\t"
   idnt = 1
   matTable = {}
   worldTable = {'ambR': 0.0, 'ambG': 0.0, 'ambB': 0.0, 'horR': 0.0, 'horG': 0.0, 'horB': 0.0} #default
   total = {'Verts': 0, 'Tris': 0, 'Faces': 0}
   
   scn = Blender.Scene.GetCurrent()

   set_up(scn, exp_list, matTable, worldTable, spawn_list)
   if not exp_list:
      #if there is nothing to export, end here
      return

   file = open(filename, "w")
   write_header(file, filename, scn, worldTable)
   write_materials(file, exp_list, worldTable, matTable)
   write_mesh(file, scn, exp_list, matTable, total)
   file.close()
   
   Blender.Window.DrawProgressBar(0, "")    # clear progressbar
   end = time.clock()
   seconds = " in %.2f %s" % (end-start, "seconds")
   totals = "Verts: %i Tris: %i Faces: %i" % (total['Verts'], total['Tris'], total['Faces'])
   print_boxed(totals)
   name = filename.split('/')[-1].split('\\')[-1]
   message = "Successfully exported " + name + seconds
   #meshtools.print_boxed(message)
   print_boxed(message)


def print_boxed(text): #Copy/Paste from meshtools, only to remove the beep :)
   lines = text.splitlines()
   maxlinelen = max(map(len, lines))
   if osSys.platform[:3] == "win":
      print chr(218)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(191)
      for line in lines:
         print chr(179) + ' ' + line.ljust(maxlinelen) + ' ' + chr(179)
      print chr(192)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(217)
   else:
      print '+-' + '-'*maxlinelen + '-+'
      for line in lines: print '| ' + line.ljust(maxlinelen) + ' |'
      print '+-' + '-'*maxlinelen + '-+'
   #print '\a\r', # beep when done

#============================================
#           Setup
#============================================

def set_up(scn, exp_list, matTable, worldTable ,worldData):


   set_lists(exp_list, worldData, matTable, worldTable)


def set_lists(exp_list, objects, matTable, worldTable):
   global mat_cnt
   mat_cnt = 0
   mat_index = 0
   #exp_list = [container1 = [ [mesh], [material_ref] ],...]

   for current_obj in objects:
	container = []
	print("mesh data add %s" % current_obj.name )
	
	if (current_obj.getType() == 'Mesh' ):
		container.append(current_obj)

		mat_type = 0 #1=Material, 2=UV Images
		mat_ref = []
		mesh = current_obj.data
		mats_me = mesh.materials
		mats_ob = current_obj.getMaterials(0)
		#Find used Materials by Meshes or Objects
		if guiTable['MTL'] == 1 and mats_me or mats_ob: #Materials
		    if mats_me:
		       me_mats = mats_me
		    elif mats_ob:
		       me_mats = mats_ob
		    mat_ref = -1

		    for i,m in matTable.iteritems():
		       for mat in me_mats:
			  if mat in m:
			     for amat in me_mats:
			        if amat not in m:
			           m.append(amat)
			     mat_ref = i
			     break

		    if mat_ref < 0:
		       matTable[mat_index] = me_mats
		       mat_ref = mat_index
		       mat_cnt+=1
		       mat_index+=1
		container.append(mat_ref)
		exp_list.append(container)

   #If there is a world shader get some values
   world = Blender.World.GetCurrent()
   if world != None:
      worldAmb = world.getAmb()
      worldHor = world.getHor()

      worldTable['ambR'] = worldAmb[0]
      worldTable['ambG'] = worldAmb[1]
      worldTable['ambB'] = worldAmb[2]

      worldTable['horR'] = worldHor[0]
      worldTable['horG'] = worldHor[1]
      worldTable['horB'] = worldHor[2]



#============================================
#           Header/Scene
#============================================

def write_header(file, filename, scn, worldTable):
   print "Write Header"

   context = scn.getRenderingContext()

   file.write("*3DSMAX_ASCIIEXPORT%s200\n" % (Tab)) 
   file.write("*COMMENT \"Exported from Blender %s - %s\"\n" % (Blender.Get('version'), time.asctime(time.localtime()))) 
   file.write("*SCENE {\n") 
   #file.write("%s*SCENE_FILENAME \"%s\"\n" % (Tab, os.path.basename(Blender.Get('filename'))))
   name = Blender.Get('filename').split('/')[-1].split('\\')[-1] #Blender 2.44
   file.write("%s*SCENE_FILENAME \"%s\"\n" % (Tab, name))

   file.write("%s*SCENE_FIRSTFRAME %d\n" % (Tab,context.startFrame()))
   file.write("%s*SCENE_LASTFRAME %d\n" % (Tab,context.endFrame()))
   file.write("%s*SCENE_FRAMESPEED %d\n" % (Tab,context.framesPerSec()))
   file.write("%s*SCENE_TICKSPERFRAME 160\n" % (Tab)) #Blender has no Ticks?

   file.write("%s*SCENE_BACKGROUND_STATIC %.4f %.4f %.4f\n" % (Tab, worldTable['horR'], worldTable['horG'], worldTable['horB']))
   file.write("%s*SCENE_AMBIENT_STATIC %.4f %.4f %.4f\n" % (Tab, worldTable['ambR'], worldTable['ambG'], worldTable['ambB']))
   file.write("}\n") 


#============================================
#           Materials
#============================================

def write_materials(file, exp_list, worldTable, matTable):
   print "Write Materials"

   file.write("*MATERIAL_LIST {\n") 
   file.write("%s*MATERIAL_COUNT %s\n" % (Tab, mat_cnt))

   for i,m in matTable.iteritems():
      if len(m) == 1: # single mat
         mat_class = 'Standard'

         mats = m
         material = mats[0]
         mat_name = material.name

         file.write("%s*MATERIAL %d {\n" % ((Tab), i))

         idnt = 2
         mat_para(file, idnt, material, mat_name, mat_class, worldTable)
         mat_dummy(file, idnt)
         mat_map(file, idnt, mat_name)

         file.write("%s}\n" % (Tab))

      elif len(m) > 1: # multiple mat
         mat_class = 'Multi/Sub-Object'

         mats = m
         material = mats[0]
         mat_name = 'Multi # ' + material.name
         submat_no = len(mats)

         idnt = 2
         file.write("%s*MATERIAL %d {\n" % ((Tab), i))

         mat_para(file, idnt, material, mat_name, mat_class, worldTable)

         file.write("%s*NUMSUBMTLS %d\n" % ((Tab*idnt), submat_no))

         for submat_cnt,current_mat in enumerate(mats):
            material = current_mat
            mat_class = 'Standard'
            mat_name = material.name

            idnt = 2
            file.write("%s*SUBMATERIAL %d {\n" % ((Tab*idnt), submat_cnt))
            submat_cnt += 1

            idnt = 3
            mat_para(file, idnt, material, mat_name, mat_class, worldTable)
            mat_dummy(file, idnt)
            mat_map(file, idnt, mat_name)

            idnt = 2
            file.write("%s}\n" % (Tab*idnt))

         file.write("%s}\n" % (Tab))


   file.write("}\n")


def mat_para(file, idnt, material, mat_name, mat_class, worldTable):

   mat_amb = material.getAmb()
   mat_dif = material.getRGBCol()
   mat_specCol = material.getSpecCol()
   mat_spec = material.getSpec()
   mat_hard = material.getHardness()
   mat_alpha = 1.0000-material.getAlpha()

   file.write("%s*MATERIAL_NAME \"%s\"\n" % ((Tab*idnt), mat_name))
   file.write("%s*MATERIAL_CLASS \"%s\"\n" % ((Tab*idnt), mat_class))
   file.write("%s*MATERIAL_AMBIENT %.4f   %.4f   %.4f\n" % ((Tab*idnt), (worldTable['ambR']*mat_amb), (worldTable['ambG']*mat_amb), (worldTable['ambB']*mat_amb))) #-Usefull?
   file.write("%s*MATERIAL_DIFFUSE %.4f   %.4f   %.4f\n" % ((Tab*idnt), mat_dif[0], mat_dif[1], mat_dif[2]))
   file.write("%s*MATERIAL_SPECULAR %.4f   %.4f   %.4f\n" % ((Tab*idnt), mat_specCol[0], mat_specCol[1], mat_specCol[2]))
   file.write("%s*MATERIAL_SHINE %.4f\n" % ((Tab*idnt), mat_spec))
   file.write("%s*MATERIAL_SHINESTRENGTH %.4f\n" % ((Tab*idnt), (mat_hard/511.))) #-511 or 512?
   file.write("%s*MATERIAL_TRANSPARENCY %.4f\n" % ((Tab*idnt), mat_alpha))
   file.write("%s*MATERIAL_WIRESIZE 1.0000\n" % (Tab*idnt))


def mat_dummy(file, idnt):

   file.write("%s*MATERIAL_SHADING Blinn\n" % (Tab*idnt))
   file.write("%s*MATERIAL_XP_FALLOFF 0.0000\n" % (Tab*idnt))
   file.write("%s*MATERIAL_SELFILLUM 0.0000\n" % (Tab*idnt))
   file.write("%s*MATERIAL_FALLOFF In\n" % (Tab*idnt))
   file.write("%s*MATERIAL_XP_TYPE Filter\n" % (Tab*idnt))


def mat_map(file, idnt, mat_name):

   mapTable = {0:'*MAP_AMBIENT',1:'*MAP_DIFFUSE',2:'*MAP_SPECULAR',3:'*MAP_SHINE',4:'*MAP_SHINESTRENGTH',5:'*MAP_SELFILLUM',6:'*MAP_OPACITY',7:'*MAP_FILTERCOLOR',8:'*MAP_BUMP',9:'*MAP_REFLECT',10:'*MAP_REFRACT',11:'*MAP_REFRACT'}
   tex_list = [[],[],[],[],[],[],[],[],[],[],[],[]]

   mat = Material.Get(mat_name)
   MTexes = mat.getTextures()

   for current_MTex in MTexes:
      if current_MTex is not None:
         # MAP_SUBNO 0 = *MAP_AMBIENT
         if current_MTex.mapto & Texture.MapTo.AMB:
            map_getTex(current_MTex, 0, (current_MTex.dvar*current_MTex.varfac), tex_list)
         # MAP_SUBNO 1 = *MAP_DIFFUSE = COL = 1
         elif current_MTex.mapto & Texture.MapTo.COL:
            map_getTex(current_MTex, 1, current_MTex.colfac, tex_list)
         # MAP_SUBNO 2 = *MAP_SPECULAR (Color)= CSP or SPEC? = 4
         elif current_MTex.mapto & Texture.MapTo.CSP:
            map_getTex(current_MTex, 2, current_MTex.colfac, tex_list)
         # MAP_SUBNO 3 = *MAP_SHINE (Spec Level) = SPEC or CSP? = 32
         elif current_MTex.mapto & Texture.MapTo.SPEC:
            map_getTex(current_MTex, 3, (current_MTex.dvar*current_MTex.varfac), tex_list)
         # MAP_SUBNO 4 = *MAP_SHINESTRENGTH (Gloss) = HARD = 256
         elif current_MTex.mapto & Texture.MapTo.HARD:
            map_getTex(current_MTex, 4, (current_MTex.dvar*current_MTex.varfac), tex_list)
         # MAP_SUBNO 5 = *MAP_SELFILLUM
         # MAP_SUBNO 6 = *MAP_OPACITY = ALPHA = 128
         elif current_MTex.mapto & Texture.MapTo.ALPHA:
            map_getTex(current_MTex, 6, (current_MTex.dvar*current_MTex.varfac), tex_list)
         # MAP_SUBNO 7 = *MAP_FILTERCOLOR
         # MAP_SUBNO 8 = *MAP_BUMP = NOR = 2
         elif current_MTex.mapto & Texture.MapTo.NOR:
            map_getTex(current_MTex, 8, (current_MTex.norfac/25), tex_list)
         # MAP_SUBNO 9 = *MAP_REFLECT
         elif current_MTex.mapto & Texture.MapTo.REF:
            map_getTex(current_MTex, 9, (current_MTex.norfac/25), tex_list)
         # MAP_SUBNO 10 = *MAP_REFRACT (refraction)
         # MAP_SUBNO 11 = *MAP_REFRACT (displacement)
         elif current_MTex.mapto & Texture.MapTo.DISP:
            map_getTex(current_MTex, 11, (current_MTex.norfac/25), tex_list)

   # Write maps
   for current_LI in tex_list:
      subNo = tex_list.index(current_LI)
      for current_MTex in current_LI:
         tex = current_MTex[0].tex
         if tex.type == Texture.Types.IMAGE:
            map_image(file, idnt, current_MTex, subNo, tex, mapTable[subNo], mat_name)


def map_getTex(MTex, map_subNo, map_amount, texes):
   # container = [[[MTex], [map_amount]], ...]
   container = []
   container.append(MTex)
   container.append(map_amount)
   texes[map_subNo].append(container)

         
def map_image(file, idnt, MTexCon, subNo, tex, mapType,mat_name):

   img = tex.getImage()
   #path = sys.expandpath(img.getFilename()).replace('/', '\\')
   #path = img.filename #or img.getFilename()
   path = ("textures/%s" % mat_name)
   tex_class = 'Bitmap'
   tex_mapType = 'Screen'
   tex_filter = 'Pyramidal'

   file.write("%s%s {\n" % ((Tab*idnt), mapType))

   idnt += 1
   file.write("%s*MAP_NAME \"%s\"\n" % ((Tab*idnt), tex.getName()))
   file.write("%s*MAP_CLASS \"%s\"\n" % ((Tab*idnt), tex_class))
   file.write("%s*MAP_SUBNO %s\n" % ((Tab*idnt), subNo))
   file.write("%s*MAP_AMOUNT %.4f\n" % ((Tab*idnt), MTexCon[1]))
   file.write("%s*BITMAP \"%s\"\n" % ((Tab*idnt), path))
   file.write("%s*MAP_TYPE %s\n" % ((Tab*idnt), tex_mapType))

   # hope this part is right!
   u_tiling = tex.repeat[0]*tex.crop[2]
   v_tiling = tex.repeat[1]*tex.crop[3]
   file.write("%s*UVW_U_OFFSET %.4f\n" % ((Tab*idnt), tex.crop[0]))
   file.write("%s*UVW_V_OFFSET %.4f\n" % ((Tab*idnt), tex.crop[1]))
   file.write("%s*UVW_U_TILING %.4f\n" % ((Tab*idnt), u_tiling))
   file.write("%s*UVW_V_TILING %.4f\n" % ((Tab*idnt), v_tiling))

   map_uvw(file, idnt) #hardcoded

   file.write("%s*BITMAP_FILTER %s\n" % ((Tab*idnt), tex_filter))

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))


def mat_uv(file, idnt, uv_image, uv_name, mat_class, worldTable):
   fake_val0 = '0.0000'
   fake_val1 = '0.1000'
   fake_val2 = '0.5882'
   fake_val3 = '0.9000'
   fake_val4 = '1.0000'

   file.write("%s*MATERIAL_NAME \"%s\"\n" % ((Tab*idnt), uv_name))
   file.write("%s*MATERIAL_CLASS \"%s\"\n" % ((Tab*idnt), mat_class))
   file.write("%s*MATERIAL_AMBIENT %.4f   %.4f   %.4f\n" % ((Tab*idnt), worldTable['ambR'], worldTable['ambG'], worldTable['ambB'])) #------------Usefull?
   file.write("%s*MATERIAL_DIFFUSE %s   %s   %s\n" % ((Tab*idnt), fake_val2, fake_val2, fake_val2))
   file.write("%s*MATERIAL_SPECULAR %s   %s   %s\n" % ((Tab*idnt), fake_val3, fake_val3, fake_val3))
   file.write("%s*MATERIAL_SHINE %s\n" % ((Tab*idnt), fake_val1))
   file.write("%s*MATERIAL_SHINESTRENGTH %s\n" % ((Tab*idnt), fake_val0))
   file.write("%s*MATERIAL_TRANSPARENCY %s\n" % ((Tab*idnt), fake_val0))
   file.write("%s*MATERIAL_WIRESIZE %s\n" % ((Tab*idnt), fake_val4))


def map_uv(file, idnt, uv_image, uv_name):
   map_type = '*MAP_DIFFUSE'
   map_subNo = '1'
   tex_class = 'Bitmap'
   tex_mapType = 'Screen'
   tex_filter = 'Pyramidal'

   fake_val0 = '0.0000'
   fake_val1 = '0.1000'
   fake_val2 = '0.5882'
   fake_val3 = '0.9000'
   fake_val4 = '1.0000'

   #replace "/" with "\" in image path
   uv_filename = uv_image.getFilename().replace('/', '\\')

   file.write("%s%s {\n" % ((Tab*idnt), map_type))

   idnt += 1
   file.write("%s*MAP_NAME \"%s\"\n" % ((Tab*idnt), uv_name))
   file.write("%s*MAP_CLASS \"%s\"\n" % ((Tab*idnt), tex_class))
   file.write("%s*MAP_SUBNO %s\n" % ((Tab*idnt), map_subNo))
   file.write("%s*MAP_AMOUNT %s\n" % ((Tab*idnt), fake_val4))
   file.write("%s*BITMAP \"%s\"\n" % ((Tab*idnt), uv_filename))
   file.write("%s*MAP_TYPE %s\n" % ((Tab*idnt), tex_mapType))
   file.write("%s*UVW_U_OFFSET %s\n" % ((Tab*idnt), fake_val0))
   file.write("%s*UVW_V_OFFSET %s\n" % ((Tab*idnt), fake_val0))
   file.write("%s*UVW_U_TILING %s\n" % ((Tab*idnt), fake_val4))
   file.write("%s*UVW_V_TILING %s\n" % ((Tab*idnt), fake_val4))

   map_uvw(file, idnt) #hardcoded

   file.write("%s*BITMAP_FILTER %s\n" % ((Tab*idnt), tex_filter))

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))


def map_uvw(file, idnt):

   fake_val0 = '0.0000'
   fake_val1 = '1.0000'

   file.write("%s*UVW_ANGLE %s\n" % ((Tab*idnt), fake_val0))
   file.write("%s*UVW_BLUR %s\n" % ((Tab*idnt), fake_val1))
   file.write("%s*UVW_BLUR_OFFSET %s\n" % ((Tab*idnt), fake_val0))
   file.write("%s*UVW_NOUSE_AMT %s\n" % ((Tab*idnt), fake_val1))
   file.write("%s*UVW_NOISE_SIZE %s\n" % ((Tab*idnt), fake_val1))
   file.write("%s*UVW_NOISE_LEVEL 1\n" % (Tab*idnt))
   file.write("%s*UVW_NOISE_PHASE %s\n" % ((Tab*idnt), fake_val0))


#============================================
#           Mesh
#============================================


def write_mesh(file, scn, exp_list, matTable, total):
   print "Write Geometric"

   for current_container in exp_list:

      TransTable = {'SizeX': 1, 'SizeY': 1, 'SizeZ': 1}
      nameMe = {'objName': 'obj', 'meName': 'me'}
      sGroups = {}
      hasTable = {'hasMat': 0, 'hasSG': 0, 'hasUV': 0, 'hasVC': 0, 'matRef': 0}
      count = {'face': 0, 'vert': 0, 'UVs': 0, 'cVert': 0}

      obj = current_container[0]
      #mat_ref = current_container[1]
      data = obj.getData(0,1)
      nameMe['objName'] = obj.name
      nameMe['meName'] = data.name

      mats_me = [mat for mat in data.materials if mat] #fix for 2.44, get rid of NoneType Objects in me.materials
      mats_ob = obj.getMaterials(0)
      materials = False

      if mats_me:
         materials = mats_me
      elif mats_ob:
         materials = mats_ob

      if guiTable['MTL'] and materials:
         hasTable['hasMat'] = 1
         hasTable['matRef'] = current_container[1]

      if obj.getParent():
         nameMe['parent'] = obj.getParent().name
      
      me = Mesh.New()      # Create a new mesh

      if guiTable['MOD']:   # Use modified mesh
         me.getFromObject(obj.name, 0) # Get the object's mesh data, cage 0 = apply mod
      else:
         me.getFromObject(obj.name, 1)

      me.transform(obj.matrix)   # ASE stores transformed mesh data
      if guiTable['RECENTER']:   # Recentre Objects to 0,0,0 feature
         rec_matrix = Mathutils.TranslationMatrix(obj.matrix.translationPart().negate())
         me.transform(rec_matrix)

      tempObj = Blender.Object.New('Mesh', 'ASE_export_temp_obj')
      tempObj.setMatrix(obj.matrix)
      tempObj.link(me)

      if guiTable['VG2SG']:
         VGNames = data.getVertGroupNames()
         for vg in VGNames:
            me.addVertGroup(vg)
            gverts = data.getVertsFromGroup(vg, 1)
            gverts_copy = []
            for gv in gverts:
               gverts_copy.append(gv[0])
            me.assignVertsToGroup(vg, gverts_copy, 1, 1)

      obj = tempObj
      faces = me.faces
      verts = me.verts

      count['vert'] = len(verts)
      total['Verts'] += count['vert']

      if count['vert'] == 0:
         print 'Error: ' + nameMe['meName'] + 'has 0 Verts'
         continue

      vGroups = me.getVertGroupNames()
      if guiTable['VG2SG'] and len(vGroups) > 0:
         for current_VG in vGroups:
            if current_VG.lower().count("smooth."):
               hasTable['hasSG'] = 1
               smooth_num = int(current_VG.lower().replace("smooth.", ""))
               gverts = me.getVertsFromGroup(current_VG)
               for vi in gverts:
                  if not sGroups.has_key(vi):
                     sGroups[vi] = [smooth_num]
                  else:
                     sGroups[vi].append(smooth_num)

      if guiTable['UV']:
         if me.faceUV == True or me.faceUV == 1:
            hasTable['hasUV'] = 1

      if guiTable['VC']:
         if me.vertexColors:
            hasTable['hasVC'] = 1
         elif hasTable['hasMat']: # Blender material
            for current_mat in materials:
               if current_mat.getMode() & Material.Modes['VCOL_PAINT']:
                  hasTable['hasVC'] = 1
                  break

      for current_face in faces:
         if len(current_face.verts) is 3:
            count['face'] += 1
            total['Tris'] += 1
            total['Faces'] += 1
         elif len(current_face.verts) is 4:
            count['face'] += 2
            total['Tris'] += 2
            total['Faces'] += 1

      #Open Geomobject
      file.write("*GEOMOBJECT {\n")
      file.write("%s*NODE_NAME \"%s\"\n" % (Tab, nameMe['objName']))

      if nameMe.has_key('parent'):
         file.write("%s*NODE_PARENT \"%s\"\n" % (Tab, nameMe['parent']))

      idnt = 1
      mesh_matrix(file, idnt, obj, nameMe, TransTable)

      #Open Mesh
      file.write("%s*MESH {\n" % (Tab))

      idnt = 2 
      file.write("%s*TIMEVALUE 0\n" % (Tab*idnt))
      file.write("%s*MESH_NUMVERTEX %i\n" % ((Tab*idnt), count['vert']))
      file.write("%s*MESH_NUMFACES %i\n" % ((Tab*idnt), count['face']))

      idnt = 2
      mesh_vertexList(file, idnt, verts, count)
      idnt = 2
      mesh_faceList(file, idnt, me, materials, sGroups, faces, matTable, hasTable, count)


      if hasTable['hasUV'] == 1:
         UVTable = {}

         active_map_channel = me.activeUVLayer
         map_channels = me.getUVLayerNames()

         idnt = 2
         mesh_tVertList(file, idnt, faces, UVTable, count)
         #idnt = 2
         mesh_tFaceList(file, idnt, faces, UVTable, count)
         UVTable = {}
         
         if len(map_channels) > 1:
            chan_index = 2
            for map_chan in map_channels:
               if map_chan != active_map_channel:
                  me.activeUVLayer = map_chan

                  idnt = 2
                  file.write("%s*MESH_MAPPINGCHANNEL %i {\n" % ((Tab*idnt), chan_index))
                  idnt = 3
                  mesh_tVertList(file, idnt, faces, UVTable, count)
                  mesh_tFaceList(file, idnt, faces, UVTable, count)
                  UVTable = {}
                  chan_index += 1
                  idnt = 2
                  file.write("%s}\n" % (Tab*idnt))

         me.activeUVLayer = active_map_channel

      else:
      # dirty fix
         file.write("%s*MESH_NUMTVERTEX %i\n" % ((Tab*idnt), count['UVs']))

      if hasTable['hasVC'] == 1:
         cVertTable = {}

         idnt = 2
         mesh_cVertList(file, idnt, faces, cVertTable, count)
         #idnt = 2
         mesh_cFaceList(file, idnt, faces, cVertTable, count)
      else:
      # dirty fix
         file.write("%s*MESH_NUMCVERTEX %i\n" % ((Tab*idnt), count['cVert']))


      idnt = 2
      mesh_normals(file, idnt, faces, verts, count)

      # Close *MESH
      idnt = 1
      file.write("%s}\n" % (Tab*idnt))

      idnt = 1
      mesh_footer(file, idnt, hasTable)

      # Close *GEOMOBJECT
      file.write("}\n")
      
      #free some memory
      me.materials = [None]
      me.faces.delete(1,[(f.index) for f in me.faces])
      me.verts.delete(me.verts)
      obj.fakeUser = False
      me.fakeUser = False
      scn.objects.unlink(obj)

def mesh_matrix(file, idnt, obj, nameMe, TransTable):

   #i should check why i have to get and invert the matrix
   #exactly in that sequence.

   row = obj.getMatrix('localspace').invert()
   #row = obj.getInverseMatrix()

   if guiTable['RECENTER']:
      location = 0.0,0.0,0.0
      row[3][0] = row[3][1] = row[3][2] = 0.0
   else:
      location = obj.getLocation()

   quat = row.invert().toQuat()
   #quat = obj.getMatrix('localspace').toQuat()
   rota = quat.axis
   #angle = quat.angle * (math.pi/180) #Blender: degrees -> ASE: radians
   angle = math.radians(quat.angle)

   Blender.Window.DrawProgressBar(0.0, "Writing Transform Node")

   file.write("%s*NODE_TM {\n" % (Tab*idnt))

   idnt += 1
   file.write("%s*NODE_NAME \"%s\"\n" % ((Tab*idnt), nameMe['meName']))
   # Inherit from what?..
   file.write("%s*INHERIT_POS 0 0 0\n" % (Tab*idnt))
   file.write("%s*INHERIT_ROT 0 0 0\n" % (Tab*idnt)) 
   file.write("%s*INHERIT_SCL 0 0 0\n" % (Tab*idnt)) 

   file.write("%s*TM_ROW0 %.4f %.4f %.4f\n" % ((Tab*idnt), row[0][0], row[0][1], row[0][2]))
   file.write("%s*TM_ROW1 %.4f %.4f %.4f\n" % ((Tab*idnt), row[1][0], row[1][1], row[1][2]))
   file.write("%s*TM_ROW2 %.4f %.4f %.4f\n" % ((Tab*idnt), row[2][0], row[2][1], row[2][2]))
   file.write("%s*TM_ROW3 %.4f %.4f %.4f\n" % ((Tab*idnt), row[3][0], row[3][1], row[3][2]))

   file.write("%s*TM_POS %.4f %.4f %.4f\n" % ((Tab*idnt), location[0], location[1], location[2]))

   file.write("%s*TM_ROTAXIS %.4f %.4f %.4f\n" % ((Tab*idnt), rota.x, rota.y, rota.z))
   file.write("%s*TM_ROTANGLE %.4f\n" % ((Tab*idnt), angle))

   file.write("%s*TM_SCALE %.4f %.4f %.4f\n" % ((Tab*idnt), TransTable['SizeX'], TransTable['SizeY'], TransTable['SizeZ']))
   #file.write("%s*TM_SCALEAXIS 0.0000 0.0000 0.0000\n" % (Tab*idnt))
   # Looks more logic, because blender use the rotaxis for rot and scale:
   file.write("%s*TM_SCALEAXIS %.4f %.4f %.4f\n" % ((Tab*idnt), rota.x, rota.y, rota.z))
   file.write("%s*TM_SCALEAXISANG %.4f\n" % ((Tab*idnt), angle))

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt)) 


def mesh_vertexList(file, idnt, verts, count):

   file.write("%s*MESH_VERTEX_LIST {\n" % (Tab*idnt)) 

   idnt += 1 

   Blender.Window.DrawProgressBar(0.0, "Writing vertices")

   for current_vert in verts:

      vIndex = current_vert.index

      if (vIndex % 1000) == 0: 
                   Blender.Window.DrawProgressBar((vIndex+1.0) / count['vert'], "Writing vertices")

      file.write("%s*MESH_VERTEX %d\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), vIndex, current_vert.co[0], current_vert.co[1], current_vert.co[2]))

   idnt -= 1 
   file.write("%s}\n" % (Tab*idnt)) 


def mesh_faceList(file, idnt, me, materials, sGroups, faces, matTable, hasTable, count):

   file.write("%s*MESH_FACE_LIST {\n" % (Tab*idnt)) 
   idnt += 1
   faceNo = 0

   Blender.Window.DrawProgressBar(0.0, "Writing faces")
   if hasTable['hasMat'] and matTable:
      mats = matTable[hasTable['matRef']]

   fgon_eds = [(ed.key) for ed in me.edges if ed.flag & Mesh.EdgeFlags.FGON]
   for current_face in faces:

      face_verts = current_face.verts
      smooth = '*MESH_SMOOTHING'
      matID = '*MESH_MTLID 0'

      if (faceNo % 500) == 0:
         Blender.Window.DrawProgressBar((faceNo+1.0) / count['face'], "Writing faces")

      if hasTable['hasMat']: # Blender mats
         #print current_face.mat
         mtlid = mats.index(materials[current_face.mat])
         matID = '*MESH_MTLID %i' % (mtlid)

      if len(face_verts) is 3:
         vert0 = face_verts[0].index
         vert1 = face_verts[1].index
         vert2 = face_verts[2].index

         #Find hidden (fgon) edges
         edge_keys = current_face.edge_keys
         eds_fgon = [1,1,1]
         for i,ed_key in enumerate(edge_keys):
            if ed_key in fgon_eds:
               eds_fgon[i] = 0

         #Find Smoothgroups for this face:
         if guiTable['VG2SG'] and hasTable['hasSG'] and current_face.smooth:
            if sGroups.has_key(vert0) and sGroups.has_key(vert1) and sGroups.has_key(vert2):
               sg = []
               gis = [sGroups[vert0],sGroups[vert1],sGroups[vert2]]
               for gil in gis:
                  for gi in gil:
                     sg.append(gi)
               sg = set(sg)
               for gi in sg:
                  smooth += ' %s,' % gi
               smooth = smooth[:-1]

         elif current_face.smooth:
            smooth += ' 1'

         file.write("%s*MESH_FACE %i:    A: %i B: %i C: %i AB:    %i BC:    %i CA:    %i\t %s \t%s\n" % ((Tab*idnt), faceNo, vert0, vert1, vert2, eds_fgon[0], eds_fgon[1], eds_fgon[2], smooth, matID))
         faceNo+=1

      elif len(face_verts) is 4:
         vert0 = face_verts[0].index
         vert1 = face_verts[1].index
         vert2 = face_verts[2].index
         vert3 = face_verts[3].index

         #Find hidden (fgon) edges
         edge_keys = current_face.edge_keys
         eds_fgon = [1,1,1,1]
         for i,ed_key in enumerate(edge_keys):
            if ed_key in fgon_eds:
               eds_fgon[i] = 0

         #Find Smooth for this face:
         if guiTable['VG2SG'] and hasTable['hasSG'] and current_face.smooth:
            if sGroups.has_key(vert0) and sGroups.has_key(vert1) and sGroups.has_key(vert2) and sGroups.has_key(vert3):
               ## I hate VG2SG ;> not sure which way is correct
               #sg0,sg1,sg2,sg3 = sGroups[vert0],sGroups[vert1],sGroups[vert2],sGroups[vert3]
               #if sg0 == sg1 == sg2 == sg3:
               #   sg = sg0
               #else:
               #   lens = [len(sg0),len(sg1),len(sg2),len(sg3)]
               #   lens_sort = lens
               #   lens_sort.sort()
               #   lowest = lens_sort[0]
               #   for l,s in zip(lens,[sg0,sg1,sg2,sg2]):
               #      if l == lowest:
               #         sg = s
               #         break

               sg = []
               gis = [sGroups[vert0],sGroups[vert1],sGroups[vert2],sGroups[vert3]]
               for gil in gis:
                  for gi in gil:
                     sg.append(gi)
               sg = set(sg)
               for gi in sg:
                  smooth += ' %s,' % gi
               smooth = smooth[:-1]
            else:
               smooth += ' 1'

         elif current_face.smooth:
            smooth += ' 1'

         file.write("%s*MESH_FACE %i:    A: %i B: %i C: %i AB:    %i BC:    %i CA:    0\t %s \t%s\n" % ((Tab*idnt), faceNo, vert0, vert1, vert2, eds_fgon[0], eds_fgon[1], smooth, matID))
         faceNo+=1
         file.write("%s*MESH_FACE %i:    A: %i B: %i C: %i AB:    %i BC:    %i CA:    0\t %s \t%s\n" % ((Tab*idnt), faceNo, vert0, vert2, vert3, eds_fgon[1], eds_fgon[2], smooth, matID))
         faceNo+=1

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))

def mesh_tVertList(file, idnt, faces, UVTable, count):

   Blender.Window.DrawProgressBar(0.0, "Setup UV index")

   for current_face in faces:
      faceuv = current_face.uv
      for current_uv in faceuv:
         uv = (current_uv.x, current_uv.y)
         if not UVTable.has_key(uv):
            UVTable[uv] = 0
            count['UVs'] += 1

   #count['UVs'] = len(UVTable)
   file.write("%s*MESH_NUMTVERTEX %d\n" % ((Tab*idnt), count['UVs']))
   file.write("%s*MESH_TVERTLIST {\n" % (Tab*idnt))

   idnt += 1
   Blender.Window.DrawProgressBar(0.0, "Writing UV index")

   for index,current_UV in enumerate(UVTable.iterkeys()):
      if (index % 1000) == 0:
         Blender.Window.DrawProgressBar((index+1.0) / count['face'], "Writing UV index")

      file.write("%s*MESH_TVERT %i\t%.4f\t%.4f\t0.0000\n" % ((Tab*idnt), index, current_UV[0], current_UV[1]))
      UVTable[current_UV] = index

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))


def mesh_tFaceList(file, idnt, faces, UVTable, count):

   tfaceNo = 0

   Blender.Window.DrawProgressBar(0.0, "Writing Face UV")

   file.write("%s*MESH_NUMTVFACES %i\n" % ((Tab*idnt), count['face']))
   file.write("%s*MESH_TFACELIST {\n" % (Tab*idnt))

   idnt += 1

   for current_face in faces:

      faceUV = current_face.uv

      if (tfaceNo % 1000) == 0:
         Blender.Window.DrawProgressBar((tfaceNo+1.0) / count['face'], "Writing Face UV")

      if len(faceUV) is 3: #tri
         UV0 = UVTable[(faceUV[0].x, faceUV[0].y)]
         UV1 = UVTable[(faceUV[1].x, faceUV[1].y)]
         UV2 = UVTable[(faceUV[2].x, faceUV[2].y)]
         file.write("%s*MESH_TFACE %i\t%i\t%i\t%d\n" % ((Tab*idnt), tfaceNo, UV0, UV1, UV2))
         tfaceNo+=1

      elif len(faceUV) is 4: #quad
         UV0 = UVTable[(faceUV[0].x, faceUV[0].y)]
         UV1 = UVTable[(faceUV[1].x, faceUV[1].y)]
         UV2 = UVTable[(faceUV[2].x, faceUV[2].y)]
         UV3 = UVTable[(faceUV[3].x, faceUV[3].y)]
         file.write("%s*MESH_TFACE %i\t%i\t%i\t%i\n" % ((Tab*idnt), tfaceNo, UV0, UV1, UV2))
         tfaceNo+=1
         file.write("%s*MESH_TFACE %i\t%i\t%i\t%i\n" % ((Tab*idnt), tfaceNo, UV0, UV2, UV3))
         tfaceNo+=1

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))


def mesh_cVertList(file, idnt, faces, cVertTable, count):

   Blender.Window.DrawProgressBar(0.0, "Setup VCol index")

   for current_face in faces:
      facecol = current_face.col
      for current_col in facecol:
         col = (current_col.r, current_col.g, current_col.b)
         if not cVertTable.has_key(col):
            cVertTable[col] = 0
            count['cVert'] += 1

   file.write("%s*MESH_NUMCVERTEX %i\n" % ((Tab*idnt), count['cVert']))
   file.write("%s*MESH_CVERTLIST {\n" % (Tab*idnt))

   idnt += 1

   Blender.Window.DrawProgressBar(0.0, "Writing VCol index")

   for index,current_cvert in enumerate(cVertTable.iterkeys()):
      if (index % 1000) == 0:
         Blender.Window.DrawProgressBar((index+1.0) / count['face'], "Writing VCol index")

      file.write("%s*MESH_VERTCOL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), index, (current_cvert[0]/256.), (current_cvert[1]/256.), (current_cvert[2]/256.)))
      cVertTable[current_cvert] = index

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))


def mesh_cFaceList(file, idnt, faces, cVertTable, count):

   cFaceNo = 0

   Blender.Window.DrawProgressBar(0.0, "Writing Face Colors")

   file.write("%s*MESH_NUMCFACES %i\n" % ((Tab*idnt), count['face']))
   file.write("%s*MESH_CFACELIST {\n" % (Tab*idnt))

   idnt += 1
   for current_face in faces:

      if (cFaceNo % 500) == 0:
         Blender.Window.DrawProgressBar((cFaceNo+1.0) / count['face'], "Writing Face Colors")

      if len(current_face.verts) is 3: #tri
         color0 = cVertTable[(current_face.col[0].r, current_face.col[0].g, current_face.col[0].b)]
         color1 = cVertTable[(current_face.col[1].r, current_face.col[1].g, current_face.col[1].b)]
         color2 = cVertTable[(current_face.col[2].r, current_face.col[2].g, current_face.col[2].b)]

         file.write("%s*MESH_CFACE %i\t%i\t%i\t%i\n" % ((Tab*idnt), cFaceNo, color0, color1, color2))
         cFaceNo+= 1

      elif len(current_face.verts) is 4: #quad
         color0 = cVertTable[(current_face.col[0].r, current_face.col[0].g, current_face.col[0].b)]
         color1 = cVertTable[(current_face.col[1].r, current_face.col[1].g, current_face.col[1].b)]
         color2 = cVertTable[(current_face.col[2].r, current_face.col[2].g, current_face.col[2].b)]
         color3 = cVertTable[(current_face.col[3].r, current_face.col[3].g, current_face.col[3].b)]

         file.write("%s*MESH_CFACE %i\t%i\t%i\t%i\n" % ((Tab*idnt), cFaceNo, color0, color1, color2))
         cFaceNo+= 1
         file.write("%s*MESH_CFACE %i\t%i\t%i\t%i\n" % ((Tab*idnt), cFaceNo, color0, color2, color3))
         cFaceNo+= 1

   idnt -= 1
   file.write("%s}\n" % (Tab*idnt))


def mesh_normals(file, idnt, faces, verts, count):
   # To export quads it is needed to calculate all face and vertex normals new!
   vec_null = Blender.Mathutils.Vector(0.0, 0.0, 0.0)
   v_normals = dict([(v.index, vec_null) for v in verts])
   f_normals = dict([(f.index, vec_null) for f in faces])
   f_normals_quad = {}

   file.write("%s*MESH_NORMALS {\n" % (Tab*idnt))

   Blender.Window.DrawProgressBar(0.0, "Setup Normals")

   #-- Calculate new face and vertex normals

   for i,f in enumerate(faces):
      f_dic = f_normals[i]
      f_vec = f_dic[0]

      f_verts = f.verts

      if len(f_verts) is 3: #tri
         v0,v1,v2 = f_verts[:]
         v0_i,v1_i,v2_i = f_verts[0].index, f_verts[1].index, f_verts[2].index
         f_no = Blender.Mathutils.TriangleNormal(v0.co, v1.co, v2.co)
         f_normals[f.index] = f_no
         if f.smooth:
            v_normals[v0_i] = v_normals[v0_i] + f_no
            v_normals[v1_i] = v_normals[v1_i] + f_no
            v_normals[v2_i] = v_normals[v2_i] + f_no

      if len(f_verts) is 4: #quad
         v0,v1,v2,v3 = f_verts[:]
         v0_i,v1_i,v2_i,v3_i = f_verts[0].index, f_verts[1].index, f_verts[2].index,f_verts[3].index
         f_no0 = Blender.Mathutils.TriangleNormal(v0.co, v1.co, v2.co)
         f_no1 = Blender.Mathutils.TriangleNormal(v2.co, v3.co, v0.co)
         f_normals[f.index] = f_no0
         f_normals_quad[f.index] = f_no1
         if f.smooth:
            v_normals[v0_i] = v_normals[v0_i] + f_no0
            v_normals[v1_i] = v_normals[v1_i] + f_no0
            v_normals[v2_i] = v_normals[v2_i] + f_no0
            
            v_normals[v0_i] = v_normals[v2_i] + f_no1
            v_normals[v2_i] = v_normals[v3_i] + f_no1
            v_normals[v3_i] = v_normals[v0_i] + f_no1


   #-- Normalize vectors
   #for i,vec in v_normals.iteritems():
   for vec in v_normals.itervalues():
      vec.normalize()

   #-- Finally write normals
   normNo = 0
   idnt += 2

   Blender.Window.DrawProgressBar(0.0, "Writing Normals")

   for f in faces:

      if (normNo % 500) == 0:
         Blender.Window.DrawProgressBar((normNo+1.0) / count['face'], "Writing Normals")

      f_verts = f.verts
      smooth = f.smooth

      if len(f_verts) is 3: #tri
         v0_i = f_verts[0].index
         v1_i = f_verts[1].index
         v2_i = f_verts[2].index

         idnt -= 1
         f_no = f_normals[f.index]
         file.write("%s*MESH_FACENORMAL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), normNo, f_no.x, f_no.y, f_no.z))
         normNo += 1

         idnt += 1
         mesh_vertNorm(file, idnt, v0_i, v1_i, v2_i, v_normals, smooth, f_no)

      #elif len(f_verts) is 4: #quad
      if len(f_verts) is 4: #quad
         v0_i = f_verts[0].index
         v1_i = f_verts[1].index
         v2_i = f_verts[2].index
         v3_i = f_verts[3].index

         idnt -= 1
         f_no = f_normals[f.index]
         file.write("%s*MESH_FACENORMAL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), normNo, f_no0.x, f_no0.y, f_no0.z))
         normNo += 1

         idnt += 1
         mesh_vertNorm(file, idnt, v0_i, v1_i, v2_i, v_normals, smooth, f_no0)

         idnt -= 1
         f_no = f_normals_quad[f.index]
         file.write("%s*MESH_FACENORMAL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), normNo, f_no1.x, f_no1.y, f_no1.z))
         normNo += 1

         idnt += 1
         mesh_vertNorm(file, idnt, v0_i, v2_i, v3_i, v_normals, smooth, f_no1)


   idnt -= 2
   file.write("%s}\n" % (Tab*idnt))
   
def mesh_vertNorm(file, idnt, v0_i, v1_i, v2_i, v_normals, smooth, f_no):
   if smooth:
      v_no0 = v_normals[v0_i]
      v_no1 = v_normals[v1_i]
      v_no2 = v_normals[v2_i]
   else: #If solid use the face normal
      v_no0 = v_no1 = v_no2 = f_no

   file.write("%s*MESH_VERTEXNORMAL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), v0_i, v_no0.x, v_no0.y, v_no0.z))
   file.write("%s*MESH_VERTEXNORMAL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), v1_i, v_no1.x, v_no1.y, v_no1.z))
   file.write("%s*MESH_VERTEXNORMAL %i\t%.4f\t%.4f\t%.4f\n" % ((Tab*idnt), v2_i, v_no2.x, v_no2.y, v_no2.z))


def mesh_footer(file, idnt, hasTable):

   file.write("%s*PROP_MOTIONBLUR 0\n" % (Tab*idnt))
   file.write("%s*PROP_CASTSHADOW 1\n" % (Tab*idnt))
   file.write("%s*PROP_RECVSHADOW 1\n" % (Tab*idnt))

   if hasTable['hasMat'] != 0:
      file.write("%s*MATERIAL_REF %i\n" % ((Tab*idnt), hasTable['matRef']))

   #-------------------------End?----------------------


def ase_compile(filename, spawn_list):

   global guiTable, EXPORT_MOD, EXPORT_MTL, EXPORT_UV, EXPORT_VC, EXPORT_SELO, EXPORT_UVI, EXPORT_VG2SG
   guiTable = {'MOD': 1, 'MTL': 1, 'UV': 1, 'VC': 1, 'SELO': 1, 'UVI': 0, 'VG2SG': 1, 'RECENTER':0}

   EXPORT_MOD = Draw.Create(guiTable['MOD'])
   EXPORT_MTL = Draw.Create(guiTable['MTL'])
   EXPORT_UV = Draw.Create(guiTable['UV'])
   EXPORT_VC = Draw.Create(guiTable['VC'])
   EXPORT_SELO = Draw.Create(guiTable['SELO'])
   EXPORT_VG2SG = Draw.Create(guiTable['VG2SG'])
   EXPORT_REC = Draw.Create(guiTable['RECENTER'])

   # Get USER Options
   #pup_block = [('Mesh Options...'),('Apply Modifiers', EXPORT_MOD, 'Use modified mesh data from each object.'),('Materials', EXPORT_MTL, 'Export Materials.'),('Face UV', EXPORT_UV, 'Export texface UV coords.'),('Vertex Colors', EXPORT_VC, 'Export vertex colors'),('Context...'),('Selection Only', EXPORT_SELO, 'Only export objects in visible selection, else export all mesh object.'),('Bonus...'),('VertGr. as SmoothGr.', EXPORT_VG2SG, 'Make SmoothGroups by VertGroups. See doc.'), ('Center Objects', EXPORT_REC, 'Center ALL objects to World-Grid-Origin-Center-Point-(0,0,0). ;)')]

  # if not Draw.PupBlock('Export...', pup_block):
  #    return

   

   guiTable['MOD'] = EXPORT_MOD.val
   guiTable['MTL'] = EXPORT_MTL.val
   guiTable['UV'] = EXPORT_UV.val
   guiTable['VC'] = EXPORT_VC.val
   guiTable['SELO'] = EXPORT_SELO.val
   guiTable['VG2SG'] = EXPORT_VG2SG.val
   guiTable['RECENTER'] = EXPORT_REC.val

   if not filename.lower().endswith('.ase'):
      filename += '.ase'
	
   writeASEFile(filename, spawn_list)
   Blender.Redraw()
   

#if __name__ == '__main__':
   #Window.FileSelector(write_ui, 'Export ASCII Scene', sys.makename(ext='.ase'))
